import json, time, sys, copy, os, re
from typing import Any

pip3_installed = False


def logger(text):
    if isinstance(text, dict) or isinstance(text, list):
        try:
            text = json.dumps(text, indent=4)
        except:
            pass
    print("[{}] {}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), text))


def check_pip3():
    logger("检查 pip3 命令")
    status = os.system("pip3 -V")
    if status != 0:
        logger("请先安装 pip3 。:(")
        exit(1)


def pip_install(name: str):
    global pip3_installed
    if not pip3_installed:
        check_pip3()
        pip3_installed = True
    cmd = f"pip3 install {name} -i https://pypi.tuna.tsinghua.edu.cn/simple"
    logger(f"尝试使用清华源安装模块 {name}: {cmd}")
    status = os.system(cmd)
    if status == 0:
        return
    cmd = f"pip3 install {name}"
    logger(f"尝试直接安装模块 {name}: {cmd}")
    status = os.system(cmd)
    if status == 0:
        return
    logger(f"模块 {name} 安装失败，请检查是否联网。:(")
    exit(1)


def get_ip(ipv4=True):
    logger("获取 IP")
    ip_regexp = re.compile(r"(\d{1,3}\.){3}\d{1,3}")
    ip_url = "https://4.ipw.cn"
    if not ipv4:
        ip_regexp = re.compile(r"([0-9a-fA-F]{1,4})?(::?[0-9a-fA-F]{1,4}){1,7}")
        ip_url = "https://6.ipw.cn"
    try:
        resp = requests.get(ip_url)
    except Exception as e:
        logger(e)
        return
    if resp.status_code > 299:
        logger(f"获取IP失败！HTTP状态码 {resp.status_code}")
        return
    ip_matched = ip_regexp.search(resp.text)
    if ip_matched:
        ip = ip_matched.group(0)
        logger("IP: " + ip)
        return ip
    else:
        logger(f"获取IP失败！正则表达式找不到IP")


try:
    import requests
except:
    pip_install("requests")
    import requests

try:
    from huaweicloudsdkcore.auth.credentials import BasicCredentials
except:
    pip_install("huaweicloudsdkcore")
    from huaweicloudsdkcore.auth.credentials import BasicCredentials

try:
    from huaweicloudsdkdns.v2.region.dns_region import DnsRegion
except:
    pip_install("huaweicloudsdkdns")
    from huaweicloudsdkdns.v2.region.dns_region import DnsRegion
from huaweicloudsdkdns.v2 import *  # type: ignore


def get_zone(client, domain_name: str):
    logger("获取zone")
    try:
        req = ListPublicZonesRequest()
        # 简单筛选根域名，例如 ddns.example.com => example.com
        reqName = re.search(r"[^\.]+\.[^\.]+$", domain_name)
        if reqName:
            req.name = reqName.group()
        resp: ListPublicZonesResponse = client.list_public_zones(req)  # type: ignore
        if not resp.status_code or resp.status_code > 299:
            logger(f"获取失败，状态码 {resp.status_code}")
            return
        zones: list[dict[str, Any]] = resp.to_dict()["zones"]
        name: str = f"{domain_name}."
        logger(zones)
        for item in zones:
            if name == item["name"]:
                return item
            if name.endswith(f".{item['name']}"):
                return item
        logger("找不到与name匹配的zone，请检查账号里有没有根域名的DNS。:(")
    except Exception as e:
        logger("获取zone失败，请检查是否断网。:(")
        logger(e)


def get_record(zone: dict[str, Any], client, domain_name: str):
    logger("获取解析")
    try:
        req = ListRecordSetsByZoneRequest(
            zone_id=zone["id"], search_mode="equal", type="A", name=domain_name
        )  # 精确查找
        resp: ListRecordSetsByZoneResponse = client.list_record_sets_by_zone(req)  # type: ignore
        if not resp.status_code or resp.status_code > 299:
            logger(f"获取失败，状态码 {resp.status_code}")
            return None
        recordsets: list[dict[str, Any]] = resp.to_dict()["recordsets"]
        if len(recordsets) > 0:
            logger("指定类型的指定域名 有 记录")
            if len(recordsets) > 1:
                logger(
                    "【警告】该域名有多条解析，请手动移除多余的解析，否则可能导致DNS服务不能正常工作！"
                )
            return recordsets[0]
        logger("指定类型的指定域名 无 记录")
        return None
    except Exception as e:
        logger(e)
        logger("获取解析失败，请检查是否断网。:(")
        return None


def set_record(credentials, ip: str, domain: dict[str, Any]):
    if ip == None:
        return False
    region = domain["region"]
    domain_name = domain["name"]
    client = (
        DnsClient.new_builder()
        .with_credentials(credentials)
        .with_region(DnsRegion.value_of(region))
        .build()
    )
    zone = get_zone(client, domain_name)
    if not zone:
        return False
    recordSet = get_record(zone, client, domain_name)
    if not recordSet:
        return False
    zoneId = zone["id"]
    try:
        if recordSet:
            records: list[str] = recordSet["records"]
            if len(records) == 1 and records[0] == ip:
                logger("解析对比IP无变化。")
                return True
            logger("正在更新解析")
            req = UpdateRecordSetRequest(
                zone_id=zoneId,
                recordset_id=recordSet["id"],
                body=UpdateRecordSetReq(
                    name=domain_name,
                    type="A",
                    ttl=300,
                    records=[ip],
                ),
            )
            resp: UpdateRecordSetResponse = client.update_record_set(req)  # type: ignore
        else:
            logger("正在创建解析")
            req = CreateRecordSetRequest(
                zone_id=zoneId,
                body=CreateRecordSetRequestBody(
                    name=domain_name,
                    type="A",
                    ttl=300,
                    records=[ip],
                ),
            )
            resp: CreateRecordSetResponse = client.create_record_set(req)  # type: ignore
        if not resp.status_code or resp.status_code > 299:
            logger(f"失败，状态码 {resp.status_code}")
            return False
        logger("解析更新成功！:D")
        return True
    except Exception as e:
        logger(e)
        logger("解析设置失败，请检查是否断网。:(")
        return False


# 子域名列表
domain_list: list[dict[str, str]] = []
# 账户名
username = ""
ak = None
sk = None

credentials = BasicCredentials(ak, sk)
ip = get_ip()
for domain in domain_list:
    set_record(credentials, ip, domain)
